package com.idealighter.game.web.checklevel.fqzs.service;

import com.google.common.collect.Table;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.dictionary.dic.FruitslotBonusNumCfgDic;
import com.idealighter.game.games.fqzs.manager.SharkMgr;
import com.idealighter.game.games.fruitslot.common.FruitslotReward;
import com.idealighter.game.games.fruitslot.common.FruitslotRewardType;
import com.idealighter.game.games.fruitslot.common.RewardCalculator;
import com.idealighter.game.games.fruitslot.dto.LineRewardIcons;
import com.idealighter.game.games.fruitslot.struct.FruistlotBasket;
import com.idealighter.game.games.fruitslot.struct.FruitslotSeat;
import com.idealighter.game.web.checklevel.fqzs.controller.dto.FqzsIconInputDto;
import com.idealighter.game.web.checklevel.fqzs.service.bo.FqzsCheckResultBo;
import com.idealighter.game.web.checklevel.shuihu.service.ShuiHuBasicControlCheck.IdCount;
import com.idealighter.utils.check.EmptyUtil;
import com.idealighter.utils.code.RandCodeUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lombok.Data;

@Singleton
public class FqzsBasicControlCheck {
  // 图标行数
  public static final int ICON_ROWS = 3;
  // 图标列数
  public static final int ICON_COLUMNS = 5;
  private static final List<Long> betList = Arrays.asList(100L, 1000L, 10000L);
  @Inject
  private FruitslotBonusNumCfgDic fruitslotBonusNumCfgDic;

  @Inject
  private SharkMgr sharkMgr;

  /**
   * 中10w次数据.
   * 
   * @Title checkList.
   */
  public FqzsCheckResultBo checkList(List<FqzsIconInputDto> basicInputs) {
    FqzsCheckResultBo result = new FqzsCheckResultBo();
    for (int i = 0; i < 1000000; i++) {
      FqzsCheckResultBo tmp = check(basicInputs);

      result.addBetChips(tmp.getBetChips());
      result.addWinChips(tmp.getWinChips());
      result.addRewardMap(tmp.getRewardMap());
      result.addIconCountMap(tmp.getIconCountMap());
    }
    return result;
  }

  /**
   * 校验.
   * 
   * @param basicInputs 基础输入.
   * @return 结果.
   */
  private FqzsCheckResultBo check(List<FqzsIconInputDto> basicInputs) {
    // icon赔率
    Map<Integer, FqzsIconInputDto> iconMap = new HashMap<Integer, FqzsIconInputDto>();
    Map<Integer, Integer> iconRates = new HashMap<Integer, Integer>();
    // icon总权值
    Integer totalIconProb = 0;
    // icon下注
    Map<Integer, Long> iconBetsMap = new HashMap<Integer, Long>();
    for (FqzsIconInputDto item : basicInputs) {
      iconMap.put(item.getIconId(), item);
      totalIconProb += item.getProb();
      iconRates.put(item.getIconId(), item.getRate());
    }
    Long totalBetChips = 0L;
    for (int i = 0; i < 100; i++) {
      Integer betIcon = RandCodeUtil.random(1, 11);
      Long betChips = RandCodeUtil.randomList(betList).longValue();
      iconBetsMap.put(betIcon, betChips);
      totalBetChips += betChips;
    }

    // 中奖图标
    int rewardIcon = randomIcon(iconMap, totalIconProb);
    // 中奖金额
    long iconRewardChips = sharkMgr.calIconRewardChips(rewardIcon, iconRates, iconBetsMap);

    FqzsCheckResultBo result = new FqzsCheckResultBo();
    result.addBetChips(totalBetChips);
    result.addWinChips(iconRewardChips);
    result.addRewardMap(rewardIcon, iconRewardChips);
    result.addIconCountMap(rewardIcon);
    return result;
  }

  private int randomIcon(Map<Integer, FqzsIconInputDto> iconMap, Integer totalIconProb) {
    // 中奖图标id
    int icon = 1;
    long randomPr = RandCodeUtil.random(totalIconProb);
    long sum = 0;
    for (FqzsIconInputDto iconRateDom : iconMap.values()) {
      sum += iconRateDom.getProb();
      if (randomPr < sum) {
        icon = iconRateDom.getIconId();
        break;
      }
    }

    return icon;
  }

  /**
   * 校验基础.
   * 
   * @param betCount 下注总计.
   * @param iconGroup 图标组合.
   * @param sglInput 输入.
   * @return 结果.
   */
  public LaBaCheckResult checkBasic(int betCount, LaBaIconGroup iconGroup, LaBaSglInput sglInput) {
    FruitslotSeat seat = new FruitslotSeat((byte) 0, null);
    LaBaCheckResult result = new LaBaCheckResult();
    for (int count = 0; count < betCount; count++) {
      seat.setLine(RandCodeUtil.random(1, 9));
      seat.setBet(RandCodeUtil.randomList(betList));
      Table<Integer, Integer, Integer> icons = seat.getIcons();

      Map<Integer, Long> itemTypeMap = new HashMap<Integer, Long>();
      boolean run = true;
      long leftBonus = 1L;
      long win = 0L;
      while (run) {
        // 合计权重
        int totalWeight = iconGroup.totalWeight;

        for (int i = 0; i < ICON_ROWS; i++) {
          for (int j = 0; j < ICON_COLUMNS; j++) {
            // 随机数
            int rand = RandCodeUtil.random(totalWeight);
            int sum = 0;
            int icon = 0;

            for (LaBaIconWeight iconWeight : iconGroup.getList()) {
              sum += iconWeight.getWeight();
              if (rand < sum) {
                icon = iconWeight.getId();
                break;
              }
            }
            icons.put(i, j, icon);
          }
        }
        FruitslotReward reward = RewardCalculator.calculate(seat.getIcons(),
            fruitslotBonusNumCfgDic.map(), seat.getLine(), seat.getBet());

        // 通过连线判断类型
        if (EmptyUtil.listIsNotEmpty(reward.getLineRewardIconsList())) {
          for (LineRewardIcons item : reward.getLineRewardIconsList()) {
            int icon = item.getIcon();
            Long typeCount = itemTypeMap.get(icon);
            if (typeCount == null) {
              typeCount = 0L;
            }
            itemTypeMap.put(icon, typeCount + 1);
          }
        }

        // 如果是水果篮奖励
        if (reward.getType() == FruitslotRewardType.LOTTERY_REWARD.getType()) {
          result.addSgl(1); // 增加水果篮次数
          // 随机产生水果篮金币
          FruistlotBasket basketRewardDomain =
              reward.getLotteryRewards().get(RandCodeUtil.random(0, 2));
          result.addWinChips(
              basketRewardDomain.getMultiple() * seat.getBet() / basketRewardDomain.getRate());
        }
        win += reward.getWin(); // 统计赢的金币
        result.addWinChips(reward.getWin());
        result.addBonus(reward.getBonus()); // 总免费把数
        leftBonus += reward.getBonus();
        leftBonus--; // 剩余bonus次数减少
        if (leftBonus <= 0) {
          run = false;
        }
      }
      if (win > 0) {
        result.addWinCount(1);
      }
      result.addBetCount(1);
      result.addBetChips(seat.getBet() * seat.getLine());
      result.addTypeMap(itemTypeMap);
    }

    return result;
  }

  /**
   * bo转dto.
   * 
   * @Title bo2dto.
   * @date 2018年1月12日 下午5:48:27
   * @param bo bo对象
   * @return Dto
   */
  public static LaBaCheckResultDto bo2dto(LaBaCheckResult bo) {
    LaBaCheckResultDto result = null;
    if (bo != null) {
      result = new LaBaCheckResultDto();
      result.setId(bo.getId());
      result.setBetChips(bo.getBetChips());
      result.setWinChips(bo.getWinChips());
      result.setBonus(bo.getBonus());
      result.setSgl(bo.getSgl());
      result.setBetCount(bo.getBetCount());
      result.setWinCount(bo.getWinCount());

      List<IdCount> list = new ArrayList<IdCount>();
      for (int id : bo.getTypeMap().keySet()) {
        Long count = bo.getTypeMap().get(id);
        IdCount item = new IdCount();
        item.setId(id);
        item.setCount(count);
        list.add(item);
      }
      result.setTypeList(list);
    }
    return result;
  }

  /**
   * bo列表转dto.
   * 
   * @Title bo2dto.
   * @author houdongsheng
   * @date 2018年1月12日 下午5:48:54
   * @param list bo列表
   * @return dto列表
   */
  public static List<LaBaCheckResultDto> bo2dto(List<LaBaCheckResult> list) {
    List<LaBaCheckResultDto> resultList = null;
    if (EmptyUtil.listIsNotEmpty(list)) {
      resultList = new ArrayList<LaBaCheckResultDto>();
      for (LaBaCheckResult item : list) {
        LaBaCheckResultDto resultItem = new LaBaCheckResultDto();
        resultItem = bo2dto(item);
        resultList.add(resultItem);
      }
    }
    return resultList;
  }

  @Data
  public static class LaBaCheckResultDto {
    private String id;
    private long betChips = 0L; // 下注金额
    private long winChips = 0L; // 赢的金币
    private long bonus = 0L; // 赢的bonus次数
    private long sgl = 0L; // 水果篮次数
    private List<IdCount> typeList = new ArrayList<IdCount>(); // 奖励情况次数， 0:普通连线奖励
    // ,全盘奖励[1:铁斧,2:银枪,3:金刀,4:鲁智深,5:林冲,6:宋江,7:替天行道,8:忠义堂,9:水浒传,10:人物,11:武器
    private long betCount = 0L; // 下注次数
    private long winCount = 0L; // 赢的把数
  }

  @Data
  public class LaBaCheckResult {
    private String id;
    private long betChips = 0L; // 下注金额
    private long winChips = 0L; // 赢的金币
    private long bonus = 0L; // 赢的bonus次数
    private long sgl = 0L; // 水果篮次数
    private Map<Integer, Long> typeMap = new HashMap<Integer, Long>(); // 奖励情况次数， 0:普通连线奖励
    // ,全盘奖励[1:铁斧,2:银枪,3:金刀,4:鲁智深,5:林冲,6:宋江,7:替天行道,8:忠义堂,9:水浒传,10:人物,11:武器
    private long betCount = 0L; // 下注次数
    private long winCount = 0L; // 赢的把数

    public void addSgl(long sgl) {
      this.sgl += sgl;
    }

    public void addBetChips(long betChips) {
      this.betChips += betChips;
    }

    public void addWinChips(long winChips) {
      this.winChips += winChips;
    }

    public void addBonus(int bonus) {
      this.bonus += bonus;
    }

    public void addBetCount(long betCount) {
      this.betCount += betCount;
    }

    public void addWinCount(long winCount) {
      this.winCount += winCount;
    }

    /**
     * .
     * 
     * @param map .
     */
    public void addTypeMap(Map<Integer, Long> map) {
      if (map != null) {
        for (Integer key : map.keySet()) {
          Long oldValue = this.typeMap.get(key);
          if (oldValue == null) {
            oldValue = 0L;
          }
          typeMap.put(key, oldValue + map.get(key));
        }
      }
    }
  }

  @Data
  public static class LaBaIconInput {
    private String id;
    private int wild;
    private int bonus;
    private int banana;
    private int watermelo;
    private int lemon;
    private int bar;
    private int grape;
    private int strawberry;
    private int cherry;
    private int apple;
    private int pawpaw;
  }

  @Data
  public static class LaBaSglInput {
    private int sglNum;
    private int sglMinRate;
    private int sglMaxRate;
  }

  public static class LaBaIconGroup {
    private int totalWeight = 0;
    private List<LaBaIconWeight> list = new ArrayList<LaBaIconWeight>();

    /**
     * 构造函数.
     * 
     * @param list .
     */
    public LaBaIconGroup(List<LaBaIconWeight> list) {
      for (LaBaIconWeight item : list) {
        this.totalWeight += item.getWeight();
        this.list.add(item);
      }
    }

    public int getTotalWeight() {
      return totalWeight;
    }

    public List<LaBaIconWeight> getList() {
      return list;
    }
  }

  @Data
  public static class LaBaIconWeight {
    private int id;
    private int weight;
  }
}
